import 'dart:convert';

import 'package:dio/dio.dart';
import 'package:film/model/film_model.dart';
import 'package:film/model/film_record_model.dart';
import 'package:film/model/sys_model.dart';
import 'package:get_storage/get_storage.dart';

class DioClient {
  DioClient._();

  static final DioClient _instance = DioClient._();
  factory DioClient() => _instance;
  static const String _baseUrl = 'http://114.132.61.19';
  static String? _token;

  static void setAuthToken(String? token) {
    _token = token;
  }

  final Dio _dio = Dio(
    BaseOptions(
      baseUrl: _baseUrl,
      connectTimeout: const Duration(seconds: 15),
      receiveTimeout: const Duration(seconds: 15),
      responseType: ResponseType.json,
    ),
  )..interceptors.add(
      InterceptorsWrapper(
        onRequest: (options, handler) {
          if (_token != null && _token!.isNotEmpty) {
            options.headers['token'] = _token;
          }
          print('REQUEST[${options.method}] => PATH: ${options.path}');
          print('HEADERS: ${options.headers}');
          print('BODY: ${options.data}');
          return handler.next(options);
        },
        onResponse: (response, handler) {
          print('RESPONSE[${response.statusCode}] => DATA: ${response.data}');
          return handler.next(response);
        },
        onError: (DioException e, handler) {
          print('ERROR[${e.response?.statusCode}] => MESSAGE: ${e.message}');
          return handler.next(e);
        },
      ),
    );

  Dio get dio => _dio;
}

class DioService {
  final Dio _dio = DioClient().dio;

  Future<ApiResponse<T>> _handleRequest<T>(
    Future<Response<dynamic>> request, {
    T Function(dynamic json)? fromJsonT,
  }) async {
    try {
      final response = await request;
      if (response.statusCode == 200) {
        final data = response.data is String ? jsonDecode(response.data) : response.data;
        return ApiResponse.fromJson(data, fromJsonT: fromJsonT);
      } else {
        throw DioException(
          requestOptions: response.requestOptions,
          response: response,
          error: 'Server returned status code ${response.statusCode}',
        );
      }
    } on DioException catch (e) {
      return ApiResponse<T>(
        success: false,
        code: e.response?.statusCode?.toString() ?? '-1',
        message: e.message ?? 'An unknown error occurred',
      );
    } catch (e) {
      return ApiResponse<T>(
        success: false,
        code: '-2',
        message: 'An unexpected error occurred: $e',
      );
    }
  }

  /// API: 用户登录
  Future<ApiResponse<String?>> login({
    required String email,
    required String password,
  }) async {
    final response = await _handleRequest<String?>(
      _dio.post(
        '/sys/login',
        data: {
          'email': email,
          'password': password,
        },
      ),
      fromJsonT: (json) => json['token'] as String?,
    );
    if (response.success && response.data != null) {
      DioClient.setAuthToken(response.data);
      final box = GetStorage();
      box.write('token', response.data);
    }
    return response;
  }

  /// API: 用户注册
  Future<ApiResponse<void>> register({
    required String email,
    required String verifyCode,
    required String password,
    String? inviteCode,
  }) async {
    return _handleRequest<void>(
      _dio.post(
        '/sys/register',
        data: {
          'email': email,
          'verifyCode': verifyCode,
          'password': password,
          'inviteCode': inviteCode ?? '',
        },
      ),
    );
  }

  /// API: 发送邮箱验证码
  Future<ApiResponse<void>> sendEmail({required String email}) async {
    return _handleRequest<void>(
      _dio.post(
        '/sys/sendEmail',
        data: {'email': email},
      ),
    );
  }

  /// API: 修改密码
  Future<ApiResponse<void>> updatePassword({
    required String email,
    required String oldPassword,
    required String newPassword,
  }) async {
    return _handleRequest<void>(
      _dio.post(
        '/sys/updatePassword',
        data: {
          'email': email,
          'oldPassword': oldPassword,
          'newPassword': newPassword,
        },
      ),
    );
  }

  /// API: 忘记密码
  Future<ApiResponse<void>> forgotPassword({
    required String email,
    required String verifyCode,
    required String newPassword,
  }) async {
    return _handleRequest<void>(
      _dio.post(
        '/sys/forgotPassword',
        data: {
          'email': email,
          'verifyCode': verifyCode,
          'newPassword': newPassword,
        },
      ),
    );
  }

  /// API: 获取用户信息
  Future<ApiResponse<UserInfo?>> getUserInfo() async {
    return _handleRequest<UserInfo?>(
      _dio.get('/sys/getUserInfo'),
      fromJsonT: (json) => UserInfo.fromJson(json['userInfo']),
    );
  }

  /// API: 更新用户信息
  Future<ApiResponse<void>> updateUserInfo({
    String? nickname,
    String? userImg,
  }) async {
    final Map<String, dynamic> payload = {};
    if (nickname != null) payload['nickname'] = nickname;
    if (userImg != null) payload['user_img'] = userImg;

    return _handleRequest<void>(
      _dio.post(
        '/sys/updateUserInfo',
        data: payload,
      ),
    );
  }

  /// API: 获取软件信息
  Future<ApiResponse<SysModel>> getSysInfo() async {
    return _handleRequest<SysModel>(
      _dio.post('/sys/getSysInfo'),
      fromJsonT: (json) => SysModel.fromJson(json['info']),
    );
  }

  /// API: 通过视频ID查询视频
  Future<ApiResponse<VideoDetails>> getVideoByID({required String vodId}) async {
    print('getVideoByID: $vodId');
    return _handleRequest<VideoDetails>(
      _dio.post(
        '/sys/getVideoByID',
        data: {'vod_id': vodId},
      ),
      fromJsonT: (json) => VideoDetails.fromJson(json),
    );
  }

  /// API: 获取视频播放地址
  Future<ApiResponse<String>> getVideoUrl({required String url}) async {
    return _handleRequest<String>(
      _dio.post(
        '/sys/getVideoUrl',
        data: {
          'MOE': '0',
          'url': url,
        },
      ),
      fromJsonT: (json) => json['url'] as String,
    );
  }

  /// API: 条件查询视频
  Future<ApiResponse<List<Film>>> searchVideo(SearchCriteria criteria) async {
    return _handleRequest<List<Film>>(
        _dio.post(
          '/sys/searchVideo',
          data: criteria.toJson(),
        ), fromJsonT: (json) {
      final List<dynamic> videoList = json['videos'] ?? [];
      return videoList.map((videoJson) => Film.fromJson(videoJson)).toList();
    });
  }

  /// API: 添加评论
  Future<ApiResponse<void>> addComment({
    required String videoId,
    required String content,
    String? parentId,
  }) async {
    return _handleRequest<void>(
      _dio.post(
        '/sys/addComment',
        data: {
          'video_id': videoId,
          'content': content,
          if (parentId != null) 'parent_id': parentId,
        },
      ),
    );
  }

  /// API: 获取评论
  Future<ApiResponse<List<Comment>>> getComments({
    String? videoId,
    String? userId,
    String? parentId,
    required int page,
    required int limit,
  }) async {
    final payload = {
      'page': page.toString(),
      'limit': limit.toString(),
      if (videoId != null) 'video_id': videoId,
      if (userId != null) 'user_id': userId,
      if (parentId != null) 'parent_id': parentId,
    };

    return _handleRequest<List<Comment>>(
        _dio.post(
          '/sys/getComments',
          data: payload,
        ), fromJsonT: (json) {
      final List<dynamic> commentList = json['comments'] ?? [];
      return commentList.map((cJson) => Comment.fromJson(cJson)).toList();
    });
  }

  /// API: 消费积分开通会员
  Future<ApiResponse<void>> openVipByPoints({required String openType}) async {
    return _handleRequest<void>(
      _dio.post(
        '/sys/openVipByPoints',
        data: {'openType': openType},
      ),
    );
  }

  /// API: 添加留言
  Future<ApiResponse<void>> addLeaveMessage({String? message_id, required String content}) async {
    return _handleRequest<void>(
      _dio.post(
        '/sys/addLeaveMessage',
        data: {
          'content': content,
        },
      ),
    );
  }

  /// API: 添加视频记录(观看记录|追番记录)
  Future<ApiResponse<void>> addVideoRecord({
    required String videoId,
    String? look,
    String? follow,
    String? watchProgress,
  }) async {
    return _handleRequest<void>(
      _dio.post(
        '/sys/addVideoRecord',
        data: {
          'video_id': videoId,
          if (look != null) 'look': look,
          if (follow != null) 'follow': follow,
          if (watchProgress != null) 'watchProgress': watchProgress,
        },
      ),
    );
  }

  /// API: 删除视频记录(观看记录|追番记录)
  Future<ApiResponse<void>> delVideoRecord({
    required String videoId,
    String? look,
    String? follow,
  }) async {
    return _handleRequest<void>(
      _dio.post(
        '/sys/delVideoRecord',
        data: {
          'video_id': videoId,
          if (look != null) 'look': look,
          if (follow != null) 'follow': follow,
        },
      ),
    );
  }

  /// API: 查询视频记录(观看记录|追番记录)
  Future<ApiResponse<List<FilmRecord>>> getVideoRecord({
    required int page,
    required int limit,
    String? videoId,
    String? look,
    String? follow,
  }) async {
    final payload = {
      'page': page.toString(),
      'limit': limit.toString(),
      if (videoId != null) 'video_id': videoId,
      if (look != null) 'look': look,
      if (follow != null) 'follow': follow,
    };

    return _handleRequest<List<FilmRecord>>(
        _dio.post(
          '/sys/getVideoRecord',
          data: payload,
        ), fromJsonT: (json) {
      final List<dynamic> filmRecordList = json['videoRecord'] ?? [];
      return filmRecordList.map((cJson) => FilmRecord.fromJson(cJson)).toList();
    });
  }
}

class ApiResponse<T> {
  final bool success;
  final String code;
  final String message;
  final T? data;
  final String? encryptedData;
  final String? iv;

  ApiResponse({
    required this.success,
    required this.code,
    required this.message,
    this.data,
    this.encryptedData,
    this.iv,
  });

  factory ApiResponse.fromJson(Map<String, dynamic> json, {T Function(dynamic json)? fromJsonT}) {
    if (json['success'] == false) {
      return ApiResponse(
        success: json['success'] ?? false,
        code: json['code']?.toString() ?? '',
        message: json['message']?.toString() ?? '',
      );
    }

    return ApiResponse(
      success: json['success'] ?? false,
      code: json['code']?.toString() ?? '',
      message: json['message']?.toString() ?? '',
      data: fromJsonT != null ? fromJsonT(json) : null,
    );
  }

  @override
  String toString() {
    return 'ApiResponse(success: $success, code: $code, message: $message, data: $data, encryptedData: $encryptedData)';
  }
}

class UserInfo {
  final int? userId;
  String? nickname;
  final String? email;
  String? userImg;
  final String? status; // 1: Banned, 2: Normal, 3: VIP
  final String? vipTime;
  final int? userPoints;
  final String? createTime;

  UserInfo({
    this.userId,
    this.nickname,
    this.email,
    this.userImg,
    this.status,
    this.vipTime,
    this.userPoints,
    this.createTime,
  });

  factory UserInfo.fromJson(Map<String, dynamic> json) {
    return UserInfo(
      userId: json['user_id'],
      nickname: json['nickname'],
      email: json['email'],
      userImg: json['user_img'],
      status: json['status'],
      vipTime: json['vip_time'],
      userPoints: json['user_points'],
      createTime: json['create_time'],
    );
  }
}

class VideoDetails {
  final Map<String, dynamic> video;
  //final Map<String, dynamic> record;

  VideoDetails({required this.video});

  factory VideoDetails.fromJson(Map<String, dynamic> json) {
    return VideoDetails(
      video: json['video'] ?? {},
      //record: json['record'] ?? {},
    );
  }
}

class SearchCriteria {
  String page;
  String limit;
  String? resultType;
  String? typeId;
  String? vodClass;
  String? vodName;
  String? vodArea;
  String? vodLang;
  String? vodYear;
  String? vodLevel;
  String? vodWeekday;

  SearchCriteria({
    required this.page,
    required this.limit,
    this.resultType,
    this.typeId,
    this.vodClass,
    this.vodName,
    this.vodArea,
    this.vodLang,
    this.vodYear,
    this.vodLevel,
    this.vodWeekday,
  });

  Map<String, dynamic> toJson() {
    final map = <String, dynamic>{};
    map['page'] = page;
    map['limit'] = limit;
    if (resultType != null) map['resultType'] = resultType;
    if (typeId != null && typeId != '') map['type_id'] = typeId;
    if (vodClass != null && vodClass != '') map['vod_class'] = vodClass;
    if (vodName != null && vodName != '') map['vod_name'] = vodName;
    if (vodArea != null && vodArea != '') map['vod_area'] = vodArea;
    if (vodLang != null && vodLang != '') map['vod_lang'] = vodLang;
    if (vodYear != null && vodYear != '') map['vod_year'] = vodYear;
    if (vodLevel != null && vodLevel != '') map['vod_level'] = vodLevel;
    if (vodWeekday != null && vodWeekday != '') map['vod_weekday'] = vodWeekday;
    return map;
  }
}

class VideoUrlInfo {
  final String url;

  VideoUrlInfo({required this.url});

  factory VideoUrlInfo.fromJson(Map<String, dynamic> json) {
    return VideoUrlInfo(url: json['url'] ?? '');
  }
}

class Comment {
  final int commentId;
  final String content;
  final String time;
  final int userId;
  final String nickname;
  final String? userImg;

  Comment({
    required this.commentId,
    required this.content,
    required this.time,
    required this.userId,
    required this.nickname,
    this.userImg,
  });

  factory Comment.fromJson(Map<String, dynamic> json) {
    return Comment(
      commentId: json['comment_id'] ?? 0,
      content: json['comment_content'] ?? '',
      time: json['comment_time'] ?? '',
      userId: json['user_id'] ?? 0,
      nickname: json['nickname'] ?? 'User',
      userImg: json['user_img'],
    );
  }
}
